package com.caishi.lkx.exam.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.common.mapper.RedisCopyDataMapper;
import com.caishi.lkx.exam.mapper.ExamMapper;
import com.caishi.lkx.exam.model.*;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.vo.IndexIndustryData;
import com.caishi.lkx.user.service.IGroupService;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.threadpool.SysThreadPool;

import com.caishi.lkx.exam.dto.UserPermissionDto;

import com.caishi.lkx.order.ienum.type.AssetsType;
import com.caishi.lkx.order.service.IUserAssetsDataService;
import com.caishi.lkx.user.model.MaterialInfoModel;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
/*@DubboService(interfaceClass = IExamBaseService.class)*/
public class ExamServiceImpl implements IExamService {

    private static final String ID_GENERATE = "exam_id_generate";

    @Resource
    private ExamMapper examMapper;

    @Resource
    private IUserAssetsDataService userAssetsDataService;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private IGroupService groupService;

    @Resource
    private IExamCalendarService examCalendarService;

    @Resource
    private IExamQuestionRankService examQuestionRankService;

    @Resource
    private IMaterialInfoService materialInfoService;

    @Resource
    private RedisCopyDataMapper redisCopyDataMapper;

    @Resource
    private IColumnService columnService;

    @Resource(name = "persistenceRedisTemplate")
    private RedisTemplate<String, Integer> redisTemplate;

    @Override
    public IBaseMapper<ExamModel, String> getMapper() {
        return examMapper;
    }

    @Override
    public String generateId(ExamModel entity) {
        var id = redisTemplate.opsForValue().increment(ID_GENERATE);
        return id == null ? "1000" : id.toString();
    }

    @PostConstruct
    public void initRedisStudentNo() {
        if (!Boolean.TRUE.equals(redisTemplate.hasKey(ID_GENERATE))) {
            String val = redisCopyDataMapper.data(ID_GENERATE);
            if (val != null) {
                log.info("系统启动，设置最新学号记录到Redis:{}", val);
                redisTemplate.opsForValue().set(ID_GENERATE, Integer.valueOf(val));
            }
        }
    }

    @PreDestroy
    public void saveRedisStudentNo() {
        try {
            log.info("系统关闭，持久化用户学号记录到数据库");
            Integer oldData = redisTemplate.opsForValue().get(ID_GENERATE);
            if (oldData != null) {
                redisCopyDataMapper.addData(ID_GENERATE, oldData.toString());
            }
        } catch (Exception e) {
            log.error("系统关闭，持久化用户学号记录到数据库 异常", e);
        }
    }


    @Override
    public List<ExamModel> industryExam(String industryId) {
        return selectList(wrappers().eq(ExamModel::getIndustryId, industryId).orderByAsc(ExamModel::getSort));
    }

    @Override
    public UserPermissionDto<String> userHaveExam(Long localGroupId, Long userGroupId, String userId) {
        var res = new UserPermissionDto<String>();
        if (StrUtil.isBlank(userId)) return res;
        var categoryIds = userAssetsDataService.userAsset(userId, AssetsType.category)
                .stream().map(v -> Long.valueOf(v.getAssetMappingId())).distinct().toList();
        var p = groupPermission(localGroupId, userGroupId, userId);
        var u = categoryIds.isEmpty() ? new LinkedList<String>() : categoryService.selectBatchIds(categoryIds).stream().map(CategoryModel::getExamId).collect(Collectors.toList());
        res.setUser(u);
        if (p != null) {
            res.setGroup(p);
        }
        return res;
    }

    @Override
    public UserPermissionDto<String> userHaveIndustry(UserPermissionDto<String> userExam) {
        var result = new UserPermissionDto<String>();
        result.setGroup(examIds2IndustryIds(userExam.getGroup()));
        result.setGroup(examIds2IndustryIds(userExam.getUser()));
        return result;
    }


    @Override
    public List<String> groupPermission(Long localGroupId, Long userGroupId, String userId) {
//        var examPermission = groupService.userGroupEnablePermission(localGroupId, userGroupId, userId);
//        var p = examPermission == null ? null : examPermission.stream()
//                .filter(v -> v.getType() == GroupPermission.Type.gjtk)
//                .findFirst()
//                .orElse(null);
//        if (p != null) {
//            if (CollUtil.isEmpty(p.getActionIds())) {
//                return new LinkedList<>();
//            } else {
//                return p.getActionIds();
//            }
//        }
        return null;
    }


    @SneakyThrows
    @Override
    public IndexIndustryData.Exam indexExamData(ExamModel examModel, boolean async) {
        var result = new IndexIndustryData.Exam();
        result.setId(examModel.getId());
        result.setName(examModel.getName());
        result.setIcon(examModel.getIcon());
        result.setAttribute(examModel.getAttribute());
        result.setIndustryId(examModel.getIndustryId());
        Callable<Integer> fr = () -> {
            var q = ExamQuestionRank.ExamQuestionRankBaseModel.builder()
                    .examId(result.getId()).build();
            // 设置热门试题
            result.setHot(examQuestionRankService.selectList(q, examQuestionRankService.wrappers()
                    .gt(ExamQuestionRank::getDoCount, 0)
                    .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, q.getExamId())
                    .orderByDesc(ExamQuestionRank::getDoCount), 10));
            // 设置易错试题
            result.setErrorRank(examQuestionRankService.selectList(q, examQuestionRankService.wrappers()
                    .gt(ExamQuestionRank::getErrorCount, 0)
                    .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, q.getExamId())
                    .orderByDesc(ExamQuestionRank::getErrorCount), 10));
            // 设置热门收藏
            result.setCollectRank(examQuestionRankService.selectList(q, examQuestionRankService.wrappers()
                    .gt(ExamQuestionRank::getCollectCount, 0)
                    .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, q.getExamId())
                    .orderByDesc(ExamQuestionRank::getCollectCount), 10));
            return 1;
        };
        var f = async ? SysThreadPool.submit(fr) : CompletableFuture.completedFuture(fr.call());
        Function<MaterialInfoModel, IndexIndustryData.SimpleMaterialInfoVo> func = model -> {
            var s = new IndexIndustryData.SimpleMaterialInfoVo();
            s.setId(model.getId());
            s.setTitle(model.getTitle());
            s.setAlias(model.getAlias());
            s.setTop(model.getTop());
            s.setHot(model.getHot());
            s.setType(model.getType());
            s.setCover(model.getCover());
            s.setDownloadTime(model.getDownloadTime());
            return s;
        };
        Callable<Integer> f1r = () -> {
            List<MaterialInfoModel> materialInfoModels = new LinkedList<>();
            //置顶推荐
            MaterialInfoModel one = materialInfoService.selectFirst(Wrappers.<MaterialInfoModel>lambdaQuery()
                    .select(BaseEntity::getId, MaterialInfoModel::getTitle, MaterialInfoModel::getAlias, MaterialInfoModel::getTop, MaterialInfoModel::getCover, MaterialInfoModel::getType)
                    .eq(MaterialInfoModel::getExamId, result.getId())
                    .eq(MaterialInfoModel::getType, false)
                    .eq(MaterialInfoModel::getRecommend, true)
                    .orderByDesc(MaterialInfoModel::getCreatedTime)
            );
            if (one != null) {
                materialInfoModels.add(one);
            }
            // 设置热门资讯
            materialInfoModels.addAll(materialInfoService.selectList(materialInfoService.wrappers()
                            .select(BaseEntity::getId, MaterialInfoModel::getTitle, MaterialInfoModel::getAlias, MaterialInfoModel::getTop, MaterialInfoModel::getCover, MaterialInfoModel::getType)
                            .eq(MaterialInfoModel::getExamId, result.getId())
                            .eq(MaterialInfoModel::getType, false)
                            .ne(null != one, MaterialInfoModel::getId, one == null ? null : one.getId())
                            .orderByDesc(MaterialInfoModel::getCreatedTime)
                            .orderByDesc(MaterialInfoModel::getDownloadTime)
                    , one == null ? 10 : 9));
            result.setHotArticle(materialInfoModels.stream().map(func).toList());
            // 设置免费资料
            result.setFreeData(materialInfoService.selectList(materialInfoService.wrappers()
                                    .select(BaseEntity::getId, MaterialInfoModel::getTitle, MaterialInfoModel::getAlias, MaterialInfoModel::getDownloadTime, MaterialInfoModel::getType, MaterialInfoModel::getAttachmentInfos)
                                    .eq(MaterialInfoModel::getExamId, result.getId())
                                    .eq(MaterialInfoModel::getType, true)
                                    .orderByAsc(MaterialInfoModel::getSort)
                                    .orderByDesc(MaterialInfoModel::getDownloadTime)
                            , 10).stream()
                    .map(v -> {
                        var s = func.apply(v);
                     /*   JSONArray jsonArray = JSONArray.parseArray(v.getAttachmentInfos());
                        int sum = 0;
                        for (int i = 0; i < jsonArray.size(); i++) {
                            var jsonObject = jsonArray.getJSONObject(i);
                            sum += (int) jsonObject.get("size");
                        }*/
                        s.setAttachmentSize(v.getAttachmentInfos().size());
                        return s;
                    }).toList());
            return 1;
        };
        var f1 = async ? SysThreadPool.submit(f1r) : CompletableFuture.completedFuture(f1r.call());
        var sourceCalendar = examCalendarService.getExamLately(result.getId());
        // 设置日历
        if (sourceCalendar != null) {
            sourceCalendar.setExamName(examModel.getServerName());
            result.setExamCalendar(examCalendarService.tansClientVo(sourceCalendar, async));
        } else {
            var m = new ExamCalendarModel();
            m.setExamId(result.getId());
            m.setExamName(examModel.getServerName());
            result.setExamCalendar(examCalendarService.tansClientVo(m, async));
        }
        f.get();
        f1.get();
        return result;
    }

    @Resource
    private IPackageService packageService;

    @Resource
    private IPackageSkuService packageSkuService;

    @Resource
    private IPackageSkuAttrService packageSkuAttrService;

    @Resource
    private IProductBaseService productBaseService;

    public void autoGenerateProduct(String examId) {
        var exam = getById(examId);
        var leafCategories = categoryService.selectList(categoryService.wrappers()
                .eq(CategoryModel::getExamId, examId)
                .apply("attribute & 1 = 1")
        );
        // 生成sku部分
        var oldList = packageSkuAttrService.selectList(packageSkuAttrService.wrappers()
                .eq(PackageSkuAttrModel::getExamId, examId)
        );
        PackageSkuAttrModel examParentSku = oldList.stream().filter(v -> v.getParentId() == null).findFirst().orElse(null);
        if (examParentSku == null) {
            examParentSku = new PackageSkuAttrModel();
            examParentSku.setExamId(examId);
            examParentSku.setName(exam.getServerName());
            examParentSku.setIndustryId(exam.getIndustryId());
            examParentSku.setId("sku_" + examId);
            packageSkuAttrService.insert(examParentSku);
        }
        PackageSkuAttrModel finalExamParentSku = examParentSku;
        leafCategories.parallelStream()
                .forEach(categoryModel -> {
                    if (oldList.stream().noneMatch(v -> v.getName().equals(categoryModel.getServerName()))) {
                        var sku = new PackageSkuAttrModel();
                        sku.setId("sku_" + examId + "_" + categoryModel.getId());
                        sku.setExamId(categoryModel.getExamId());
                        sku.setName(categoryModel.getServerName());
                        sku.setIndustryId(categoryModel.getIndustryId());
                        sku.setParentId(finalExamParentSku.getId());
                        packageSkuAttrService.insert(sku);
                    }
                });
        // 生成基础产品
        leafCategories.parallelStream().forEach(category -> {
            if (productBaseService.selectCount(productBaseService.wrappers()
                    .eq(ProductBaseModel::getCategoryId, category.getId())
            ) > 0) return;
            var model = new ProductBaseModel();
            model.setName(category.getServerName());
            model.setIndustryId(category.getIndustryId());
            model.setExamId(category.getExamId());
            model.setCategoryId(category.getId());
            model.setSort(category.getSort());
            model.setColumnIds(columnService.selectList(columnService.wrappers().eq(ColumnModel::getCategoryId, category.getId())).stream().map(BaseEntity::getId).toList());
            productBaseService.insert(model);
        });
        // 管理套餐
        PackageModel packageModel = packageService.selectFirst(packageService.wrappers()
                .eq(PackageModel::getExamId, examId)
        );
        var packageInsert = packageModel == null;
        if (packageModel == null) {
            packageModel = new PackageModel();
            packageModel.setName(exam.getServerName());
            packageModel.setIndustryId(exam.getIndustryId());
            packageModel.setExamId(examId);
            packageModel.setPrice(4000L);
            packageModel.setDiscountPrice(2000L);
            packageModel.setAgentPrice(1000L);
            packageModel.setTmPrice(1000L);
            packageModel.setDays(365);
            packageModel.setEnable(true);
        }
        var skus = packageSkuAttrService.selectList(packageSkuAttrService.wrappers()
                .eq(PackageSkuAttrModel::getExamId, examId)
                .isNotNull(PackageSkuAttrModel::getParentId)
        );
        packageModel.setSkuAttrs(MapUtil.<String, Object>builder()
                .put("guige", List.of("danke"))
                .put(examParentSku.getId(), skus.stream().map(BaseEntity::getId).toList())
                .build());
        if (packageInsert) packageService.insert(packageModel);
        else packageService.update(packageModel);
        // 生成sku_attr
        var oldSkuAttr = packageSkuService.selectList(packageSkuService.wrappers()
                .eq(PackageSkuModel::getPackageId, packageModel.getId())
        );
        var products = productBaseService.selectList(productBaseService.wrappers()
                .eq(ProductBaseModel::getExamId, examId)
        );
        for (var sku : skus) {
            if (oldSkuAttr.stream().anyMatch(v -> v.getSkuAttrIds().contains(v.getId()))) continue;
            var model = new PackageSkuModel();
            model.setName(sku.getName());
            model.setIndustryId(sku.getIndustryId());
            model.setExamId(sku.getExamId());
            model.setPackageId(packageModel.getId());
            model.setPrice(packageModel.getPrice());
            model.setDiscountPrice(packageModel.getDiscountPrice());
            model.setAgentPrice(packageModel.getAgentPrice());
            model.setTmPrice(packageModel.getTmPrice());
            model.setSkuAttrIds(List.of("danke", sku.getId()));
            var product = products.stream().filter(v -> v.getName().equals(sku.getName())).findFirst().orElse(null);
            if (product == null) {
                log.error("没找到基础产品 skuname={} examId={}", sku.getName(), examId);
                continue;
            }
            model.setProductIds(List.of(product.getId()));
            model.setCategoryIds(List.of(product.getCategoryId()));
            packageSkuService.insert(model);
        }
    }


    private List<String> examIds2IndustryIds(List<String> examIds) {
        if (CollUtil.isEmpty(examIds)) return new LinkedList<>();
        return selectList(wrappers().select(ExamModel::getIndustryId).in(BaseEntity::getId, examIds))
                .stream().map(ExamModel::getIndustryId).collect(Collectors.toList());
    }

    public static void main(String[] args) {
        System.out.println("1087".hashCode() & 31);
    }
//
//    @Override
//    public List<RpcExamModel> rpcGetList(String hyId) {
//        List<ExamModel> examList = examMapper.selectList(Wrappers.<ExamModel>lambdaQuery().eq(ExamModel::getIndustryId, hyId));
//        return examList.stream().map(RpcExamModel::model).collect(Collectors.toList());
//    }
//
//    @Override
//    public List<RpcExamModel> rpcGetListByIds(List<String> examIds) {
//        if (null == examIds || examIds.isEmpty()) {
//            return null;
//        }
//        List<ExamModel> examModels = this.selectList(Wrappers.<ExamModel>lambdaQuery()
//                .in(ExamModel::getId, examIds).orderByAsc(ExamModel::getSort));
//        return examModels.stream().map(v -> BeanUtil.copyProperties(v, RpcExamModel.class)).collect(Collectors.toList());
//    }
//
//    @Override
//    public RpcExamModel rpcGetById(String id) {
//        ExamModel examModel = this.getById(id);
//        return BeanUtil.copyProperties(examModel, RpcExamModel.class);
//    }
}
